package cn.jtool.dig.common.model;

import com.google.common.collect.Maps;
import io.netty.channel.ChannelHandlerContext;
import lombok.*;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Session implements Serializable {

    private long id;

    private Integer licenseId;

    private Integer portMappingId;

    private SessionType sessionType = SessionType.TUNNEL;

    private Date createTime;

    private Date updateTime;

    private Long heartbeatTime;

    private AtomicLong receiveBytes = new AtomicLong(0);
    private AtomicLong sendBytes = new AtomicLong(0);

    private AtomicLong receiveBytesSegment = new AtomicLong(0);
    private AtomicLong sendBytesSegment = new AtomicLong(0);

    private ChannelHandlerContext channelHandlerContext;

    /**
     * 虚拟通道是否正常
     */
    private Boolean virtualIsOk;

    private byte[] surplus;

    public void disconnect(){
        if(Objects.nonNull(this.channelHandlerContext)){
            this.channelHandlerContext.channel().close();
        }
    }

    public boolean isConnect(){
        return Objects.nonNull(this.channelHandlerContext) && this.channelHandlerContext.channel().isActive();
    }

    public void addReceiveByte(int number){
        this.receiveBytes.addAndGet(number);
    }
    public void addSendByte(int number){
        this.sendBytes.addAndGet(number);
    }

    public Long getReceiveBytes(){
        return this.receiveBytes.get();
    }
    public Long getSendBytes(){
        return this.sendBytes.get();
    }


    public void addTrafficBySegment(TrafficDir dir, long number){
        if(dir == TrafficDir.REC){
            if(Objects.isNull(this.receiveBytesSegment)){
                this.receiveBytesSegment = new AtomicLong(0);
            }
            this.receiveBytesSegment.addAndGet(number);
        }else if(dir == TrafficDir.SEND){
            if(Objects.isNull(this.sendBytesSegment)){
                this.sendBytesSegment = new AtomicLong(0);
            }
            this.sendBytesSegment.addAndGet(number);
        }
    }

    public Long getTrafficBySegment(TrafficDir dir, boolean isReset){
        if(dir == TrafficDir.REC){
            return Objects.isNull(this.receiveBytesSegment) ? 0 : isReset ? this.receiveBytesSegment.getAndSet(0) : this.receiveBytesSegment.get();
        }else if(dir == TrafficDir.SEND){
            return Objects.isNull(this.sendBytesSegment) ? 0 : isReset ? this.sendBytesSegment.getAndSet(0) : this.sendBytesSegment.get();
        }
        return 0L;
    }
    /**
     * 链路类型
     */
    @Getter
    @AllArgsConstructor
    public enum SessionType implements Serializable{
        /**
         * 真实接入链路
         */
        REAL("REAL", "真实接入链路"),
        /**
         * 隧道接入链路
         */
        TUNNEL("TUNNEL", "隧道接入链路");

        private static Map<String, SessionType> map = Maps.newHashMap();
        static {
            Arrays.stream(values()).forEach(e->{
                map.put(e.code, e);
            });
        }
        private final String code;
        private final String name;

        public static SessionType valueOfCode(String code){
            return map.get(code);
        }
    }

    /**
     * 链路状态
     */
    @Getter
    @AllArgsConstructor
    public enum SessionStatus implements Serializable{
        PREPARING,READYING,CLOSEING
    }

    @Getter
    @AllArgsConstructor
    public enum TrafficDir implements Serializable{
        REC,SEND
    }

}
